#ifndef __M_MqHelper_H__
#define __M_MqHelper_H__
#include"logger.hpp"
#include<iostream>
#include<sqlite3.h>
#include<vector>
#include<random>
#include<sstream>
#include<iomanip>
#include<atomic>
#include <stdlib.h>
#include<sys/stat.h>
#include<functional>
#include<fstream>
#include<cstring>
#include<cerrno>
#include<stdio.h>
#include <filesystem>

namespace mq{
    class SqliteHelper{
    typedef int(*SqliteCallback)(void*,int,char**,char**);
    public:
        SqliteHelper(const std::string& dbpath):_db_filepath(dbpath),_hander(nullptr){
        }
        bool open(){
            int ret = sqlite3_open_v2(_db_filepath.c_str(),&_hander,SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE
             | SQLITE_OPEN_FULLMUTEX,nullptr);
             if(ret != SQLITE_OK){
                LOG_ERRORM("sqlite open false... %s",sqlite3_errmsg(_hander))
                return false;
             }
             return true;
        }
        bool exec(const std::string& sql,SqliteCallback cb,void* arg){
            //sqlite3_exec(sqlite3*, char *sql, int (*callback)(void*, int, char**, char**),void* arg, char **err)
            int ret = sqlite3_exec(_hander,sql.c_str(),cb,arg,nullptr);
            if(ret != SQLITE_OK){
                LOG_ERRORM("sqlite exec false... %s",sqlite3_errmsg(_hander))
                return false;
            }
            return true;
        }
        bool close(){
            int ret = sqlite3_close_v2(_hander);
            if(ret != SQLITE_OK){
                LOG_ERRORM("sqlite close false... %s",sqlite3_errmsg(_hander))
                return false;
            }
            return true; 
        }
    private:
        sqlite3* _hander;
        std::string _db_filepath;
    };

    class Stringsplit{
        public:
        static size_t split (const std::string& input,std::vector<std::string>* output,const std::string& sep){
            output->clear();
            size_t left = 0,right= 0;
            while(right < input.size()){
                right = input.find(sep.c_str(),left);
                if(right == std::string::npos) {
                    if(left < input.size())
                        output->push_back(input.substr(left));
                    break;
                }
                if(right == left){
                    left = right + sep.size();
                    continue;
                }
                output->push_back(input.substr(left,right-left));
                left = right + sep.size();
            }
            return output->size();
        }   
    };

    class Uuidhelper{
    public:
    static std::string BuideUuid(){
        std::random_device rd;
        std::mt19937_64 gernator (rd());
        std::uniform_int_distribution<int> distribution(0,255);
        std::stringstream ss;
        for(int i = 0 ;i < 8;i++){
            ss << std::setw(2) <<std::setfill('0') << std::hex << distribution(gernator);
            if(i == 3 || i == 5 || i == 7){
                ss<<'-';
            }
        }
        static std::atomic<size_t> atonum(1);
        size_t num = atonum.fetch_add(1);//unsi long 
        for(int i = 7;i >= 0 ;i--){
            ss << std::setw(2) << std::setfill('0') << std::hex << ((num<<(i*8)) & 0xff);
        }
        return ss.str();
    }
    };

    class Filehelper{
    public:
        Filehelper(const std::string& filename):_filename(filename){}

        static bool exists(const std::string& filename){
            struct stat st;
            return (stat(filename.c_str(),&st) == 0);
        }
        bool exists(){
            struct stat st;
            return (stat(_filename.c_str(),&st) == 0);
        }

        static size_t size(const std::string& filename){
            struct stat st;
            if(stat(filename.c_str(),&st) != 0){
                return 0;
            }
            return st.st_size;
        }
        size_t size(){
            struct stat st;
            if(stat(_filename.c_str(),&st) != 0){
                return 0;
            }
            return st.st_size;
        }

        bool read(std::string* body,size_t offset,size_t len){
            body->resize(len);
            std::ifstream ifs(_filename, std::ios::binary | std::ios::in);
            if(!ifs.is_open()){
                LOG_ERRORM("open read false...");
                return false;
            }
            ifs.seekg(offset);
            ifs.read(&(*body)[0],len);
            if(!ifs.good()){
                LOG_ERRORM("read false...");
                return false;
            }
            ifs.close();
            return true;
        }

        bool read(char* body,size_t offset,size_t len){
            std::ifstream ifs(_filename, std::ios::binary | std::ios::in);
            if(!ifs.is_open()){
                LOG_ERRORM("open read false...");
                return false;
            }
            ifs.seekg(offset);
            ifs.read(body,len);
            if(!ifs.good()){
                LOG_ERRORM("read false...");
                return false;
            }
            ifs.close();
            return true;
        }

        bool read(std::string* body){
            size_t len = Filehelper::size();
            return Filehelper::read(body,0,len);
        }

        // bool write(const std::string& body,size_t offset,size_t len){
        //     std::fstream fs(_filename,std::ios::binary | std::ios::in | std::ios::out);
        //     if(!fs.is_open()){
        //         LOG_ERROR("open write false...");
        //         return false;
        //     }
        //     if (offset > fs.tellg()) {
        //         LOG_ERROR("offset %ld beyond file size", offset);
        //         return false;
        //     }

        //     fs.seekp(offset, std::ios::beg);
        //     fs.write(body.c_str(),len);
        //     if(!fs.good()){
        //         LOG_ERROR("write false...");
        //         return false;
        //     }
        //     fs.close();
        //     return true;
        // }

        bool write(const char *body, size_t offset, size_t len) {
            //1. 打开文件
            std::fstream fs(_filename, std::ios::binary | std::ios::in | std::ios::out);
            if (fs.is_open() == false) {
            LOG_ERRORM("%s 文件打开失败！ ", _filename.c_str());
            return false;
            }
            //2. 跳转到文件指定位置
            fs.seekp(offset, std::ios::beg);
            //3. 写入数据
            fs.write(body, len);
            if (fs.good() == false) {
            LOG_ERRORM("%s 文件写入数据失败！！ ", _filename.c_str());
            fs.close();
            return false;
            }
            //4. 关闭文件
            fs.close();
            return true;
        }

        bool write(const std::string& body){
            //  有bug 会覆写 
            return Filehelper::write(body.c_str(),0,body.size());
        }

        static bool createFile(const std::string& filename){
            std::ofstream of(filename,std::ios::binary | std::ios::out);
            if(!of.is_open()){
                LOG_ERRORM("creatfile false + %s",filename.c_str());
                return false;
            }
            of.close();
            return true;
        }

        bool createFile(){
            std::ofstream of(_filename,std::ios::binary | std::ios::out);
            if(!of.is_open()){
                LOG_ERRORM("creatfile false + %s",_filename.c_str());
                return false;
            }
            of.close();

            return true;
        }
        static bool removeFile(const std::string& filename){
            return (::remove(filename.c_str()) == 0);
        }
        
        bool removeFile(){
            return (::remove(_filename.c_str()) == 0);
        }

        static bool createDirectory(const std::string& path){
            // ./a/b    a/b/c
            const std::string sep = "/";

            size_t start = 0,end;
            while(start < path.size()){
                end = path.find('/',start);
                if(end == std::string::npos){
                    std::string subpath = path;
                    mkdir(subpath.c_str(),0775);
                    return true;
                }
                std::string subpath = path.substr(0,end);
                int ret = mkdir(subpath.c_str(),0775); 
                if(ret != 0 && errno != EEXIST){
                    //eexist !!! 一开始有一个./ 所以要忽略
                    LOG_ERRORM("create %s Directory false... %s",path.c_str(),strerror(errno));
                    return false;
                }
                start = end + sep.size();
            }
            return true;
        }
        bool removeDirectory(){
            if(_filename == "/")    
                return false;
            std::string comd = "rm -rf" + _filename;
            return (system(comd.c_str()) != -1);
        }

        static std::string parentDirectory(const std::string& filename){
            size_t pos = filename.rfind('/');
            if(pos == std::string::npos){
                return "./";
            }
            std::string path = filename.substr(0,pos);
            return path;
        }

        static bool renameFile(const std::string& old_name, const std::string& new_name) {
            if (std::rename(old_name.c_str(), new_name.c_str()) == 0) {
                return true;
            } else {
                std::cerr << "重命名失败: " << std::strerror(errno) << std::endl;
                return false;
            }
        }

    private:
        std::string _filename;
    };
    
}
#endif